/*************************************************************/
// Filename: shared_ptr.hpp
// Date: 2010-12-14
// Auther: Meixueting <wolfhead87@gmail.com>
// Purpose: shared pointer
//			thread unsafe
/*************************************************************/
#ifndef ACAPELLA_SHARED_PTR_HPP_
#define ACAPELLA_SHARED_PTR_HPP_

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>

#include <acapella/acapella.h>
#include <acapella/traits/traits.h>
#include <acapella/traits/type_traits.hpp>
#include <acapella/synchronize/synchronize.h>



namespace acapella
{


namespace __detail__
{

    /**
     * count_base 
     * maintain a counter on a given entity
     */
    template<
        typename ContentPolicy, 
        typename ThreadPolicy>
 	struct count_base
	{
		count_base() : count(0){}

		_uint32_ count;
        ThreadPolicy threadPolicy;


		inline operator unsigned int() {return count;}
		inline void ref() 
		{

			threadPolicy.lock();

			++count;

			threadPolicy.unlock();

		}

		inline void release(typename ContentPolicy::ContentType p)
		{
			threadPolicy.lock();

			_uint32_ newcount = --count;

			threadPolicy.unlock();

			if (newcount == 0)
			{
                ContentPolicy::destroy(p);
				dispose();
			}

		}

		inline void dispose()
		{
			delete this;
		}
	};

    /**
     * shared_count
     * handler assignment and copy construct
     * and hold the content
     */
	template <
        typename T, 
        template<class> class _ContentPolicy,
        class ThreadPolicy>
	class shared_count
	{
    private:
        typedef _ContentPolicy<T> ContentPolicy;
        typedef typename ContentPolicy::ContentType ContentType;
	public:
        ContentType content_;
		count_base<ContentPolicy, ThreadPolicy>* pCounter_;

	public:
		inline ContentType get() const {return content_;};

		~shared_count()
        {
            pCounter_->release(content_);
        }

		shared_count()
            : content_(ContentPolicy::initialize())
            , pCounter_(new count_base<ContentPolicy, ThreadPolicy>)
		{
			pCounter_->ref();
		}

		shared_count(const ContentType& _content)
		{
			pCounter_ = new count_base<ContentPolicy, ThreadPolicy>;
			this->content_ = _content;
			pCounter_->ref();
		}

		shared_count(const shared_count & r)
		{
			content_ = r.content_;
			pCounter_ = r.pCounter_;
			pCounter_->ref();
		}

		template<typename Y>
		shared_count(const shared_count<Y, _ContentPolicy, ThreadPolicy> & r)
		{
			content_ = r.content_;
			pCounter_ = r.pCounter_;
			pCounter_->ref();
		}

		shared_count& operator=(const shared_count & r)
		{
            // assign between same content
			if (r.pCounter_ == pCounter_) {
				return *this;
			} else {

				pCounter_->release(content_);

				pCounter_ = r.pCounter_;
				content_ = r.content_;
				pCounter_->ref();
				return *this;
			}
		}

        
        _uint32_ count() const
        {
            return pCounter_->count;
        }
	};
}//namespace __detail__


    template<typename T>
    struct ObjectPointerContent
    {
        typedef T * ContentType;

        static ContentType initialize()
        {
            return 0;
        }

        static void destroy(ContentType content)
        {
            if (content != 0)
            {
                delete content;
            }
        }
    };

    template<typename T>
    struct ArrayPointerContent
    {
        typedef T * ContentType;

        static ContentType initialize()
        {
            return NULL;
        }

        static void destroy(ContentType content)
        {
            if (content != NULL)
            {
                delete [] content;
            }
        }
    };

    template<typename T>
    struct HandleContent
    {
        typedef T ContentType;

        static ContentType initialize()
        {
            return -1;
        }


        static void destroy(ContentType content)
        {
            if (content != -1)
            {
                ::close(content);
            }
        }
    };

    template<typename T>
    struct FileContent
    {
        typedef T ContentType;

        static ContentType initialize()
        {
            return NULL;
        }

        static void destroy(ContentType content)
        {
            if (content != NULL)
            {
                ::fclose(content);
            }
        }
    };

    template<typename T>
    struct DirContent
    {
        typedef T ContentType;
        
        static ContentType initialize()
        {
            return NULL;
        }

        static void destroy(ContentType content)
        {
            if (content != NULL)
            {
                ::closedir(content);
            }
        }
    };

    struct NonThread
    {
        void lock(){};
        void unlock(){};
    };

    struct HasThread
    {
        void lock() {spin.lock();}
        void unlock() {spin.unlock();}

        acapella::synchronize::spin_lock spin;
    };



	template<
        typename T, 
        template <class> class _ContentPolicy = ObjectPointerContent,
        class ThreadPolicy = NonThread
        > 
	class shared_ptr
	{
	public:
        typedef _ContentPolicy<T> ContentPolicy;
        typedef typename ContentPolicy::ContentType ContentType;
		typedef __detail__::shared_count<T, _ContentPolicy, ThreadPolicy> counter;

	public:
		shared_ptr() : x() {}

		explicit shared_ptr(ContentType p) : x(p) {}

		template<typename Y>
		shared_ptr(const shared_ptr<Y> & r) : x(r.x){};

		template<typename Y>
		shared_ptr& operator=(const shared_ptr<Y> & r)
		{
			x = r.x;
			return *this;
		}


		shared_ptr& operator=(const shared_ptr & r)
		{
			x = r.x;
			return *this;
		}

        typename traits::TypeTraits<ContentType>::ElementType &
        operator* () const
		{
			return *(x.get());
		}

		operator ContentType() const
		{
			return x.get();
		}

		ContentType operator->() const
		{
			return x.get();
		}

		ContentType get() const
		{
			return x.get();
		}

        _uint32_ count() const
        {
            return x.count();
        }

	public:
		counter x;
	};


    /**
     * Comparation
     * 
     */
	template<class T, class U> inline bool operator==(const shared_ptr<T> & a, shared_ptr<U> & b)
	{
		return a.get() == b.get();
	}

	template<class T, class U> inline bool operator!=(const shared_ptr<T> & a, const shared_ptr<U> & b)
	{
		return a.get() != b.get();
	}

	template<class T, class U> inline bool operator>(const shared_ptr<T> & a, const shared_ptr<U> & b)
	{
		return a.get() > b.get();
	}

	template<class T, class U> inline bool operator>=(const shared_ptr<T> & a, const shared_ptr<U> & b)
	{
		return a.get() >= b.get();
	}

	template<class T, class U> inline bool operator<(const shared_ptr<T> & a,const shared_ptr<U> & b)
	{
		return a.get() < b.get();
	}

	template<class T, class U> inline bool operator<=(const shared_ptr<T> & a, const shared_ptr<U> & b)
	{
		return a.get() <= b.get();
	}



	// define shared pointer traits
	namespace traits
	{
		template<typename T>
		struct poiner_traits<acapella::shared_ptr<T> >
		{
			typedef typename element_type<T>::type element_type;
		};
	}
}

#endif

